package me.seawenc.db.checker.helper;

import java.util.Collection;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.function.Supplier;

/**
 * Optional对判空不友好,它只认为null为空,我们需要空串,list.size=0也为空, 增强此类
 * @param <T>
 */
public class Optionalx<T> {

    /**
     * 定义空Optionalx
     */
    private static final Optionalx<?> EMPTY = new Optionalx<>();

    /**
     * value
     */
    private final T value;



    /**
     * ofNullable
     * @param value value
     * @param <T> T
     * @return Optional<T>
     */
    public static <T> Optional<T> ofNullable(T value){
        boolean empty = isEmpty(value);
        return Optional.ofNullable(empty?null:value);
    }

    /**
     * ifPresent
     * @param value value
     * @param f f
     * @param <T> T
     */
    public static <T> void ifPresent(T value, Consumer<T> f){
        ofNullable(value).ifPresent(f);
    }

    /**
     * ifNotPresent
     * @param value value
     * @param r r
     * @param <T> T
     */
    public static <T> void ifNotPresent(T value, Runnable r){
        if(!isPresent(value)){
            r.run();
        }
    }

    /**
     * ifPresentAndRet
     * @param value value
     * @param f f
     * @param def def
     * @param <T> T
     * @return T
     */
    public static <T> T ifPresentAndRet(T value, Function<T,T> f,T def){
        if(isPresent(value)){
            return f.apply(value);
        }
        return def;
    }

    /**
     * 如果存在就断言，为真，则执行fun函数并返回结果，否则返回默认值
     * @param value  需要处理的对象
     * @param predicate 断言value对旬
     * @param fun  如果为真了，直接此函数
     * @param def   默认值
     * @param <T>   参数与返回值类型
     * @return
     */
    public static <T> T ifPresentThen(T value, Predicate<T> predicate, Function<T,T> fun, T... def){
        if(isNotPresent(value)){
            return def.length>0?def[0]:null;
        }
        if(predicate.test(value)){
            return fun.apply(value);
        }
        return def.length>0?def[0]:null;
    }

    /**
     * 如果value存在，则执行函数：predicate
     * @param value
     * @param predicate 函数
     * @param <T>
     */
    public static <T> void ifPresentThen(T value, Consumer<T> predicate){
        if(isPresent(value)){
            predicate.accept(value);
        }
    }

    /**
     *
     * @param ifCmd   断言函数 必須返回boolean值
     * @param then    断言为真时执行此函数，并返回执行结果
     * @param def     默认值
     * @param <T>
     * @return
     */
    public static <T> T ifThen(IfCmd ifCmd, Supplier<T> then, T... def){
        if(ifCmd.test()){
            return then.get();
        }
        return def.length>0?def[0]:null;
    }

    /**
     * ifThen
     * @param ifCmd ifCmd
     * @param then then
     */
    public static void ifThen(IfCmd ifCmd, Runnable then){
        if(ifCmd.test()){
            then.run();
        }
    }

    public static void ifThen(boolean isBoolean, Runnable then){
        if(isBoolean){
            then.run();
        }
    }
    /**
     * ifThen
     * @param value value
     * @param ifCmd ifCmd
     * @param then then
     * @param def def
     * @param <T> T
     * @return T
     */
    public static <T> T ifThen(T value,Predicate<T> ifCmd, Function<T,T> then, T... def){
        if(ifCmd.test(value)){
            return then.apply(value);
        }
        return def.length>0?def[0]:null;
    }

    /**
     * ofByDef
     * @param value value
     * @param defs defs
     * @param <T> T
     * @return Optional<T>
     */
    public static <T> Optional<T> ofByDef(T value,T... defs){
        return Optional.ofNullable(ofByDefGet(value,defs));
    }

    /**
     * isPresent
     * @param value value
     * @return boolean
     */
    public static boolean isPresent(Object value){
        return isNotEmpty(value);
    }

    /**
     * isPresent
     * @param value 数组
     * @return boolean
     */
    public static boolean isPresent(Object[] value){
        return isNotEmpty(value);
    }

    /**
     * isNotPresent
     * @param value value
     * @return boolean
     */
    public static boolean isNotPresent(Object value){
        return !isPresent(value);
    }

    /**
     * ofByDefGet
     * @param values values
     * @param def def
     * @param <T> T
     * @return T[]
     */
    public static <T> T[] ofByDefGet(T[] values,T[] def){
        return (values==null||values.length==0)?def:values;
    }
    /**
     * 若为空,则返回默认值
     * @param value 需要判断的值
     * @param defs 如果为空后的默认值
     * @param <T>
     * @return
     */
    public static <T> T ofByDefGet(T value,T... defs){
        if(isNotEmpty(value)){
            return value;
        }
        for(T t:defs){
            if(isNotEmpty(t)){
                return t;
            }
        }
        //返回最后一个
        return value;
    }

    /**
     * 如果为空以后的默认参数需要计算，则用此方法，以实现需要时才计算
     * @param value 需要判断的值
     * @param def  value为空后，默认的对象生成器
     * @param <T>
     * @return
     */
    public static <T> T ofByDefGet(T value,Supplier<T> def){
        if(isNotEmpty(value)){
            return value;
        }
        return def.get();
    }

    /**
     * IfCmd
     */
    public interface IfCmd {
        boolean test();
    }

    /**
     * of
     * @param value value
     * @param <T> T
     * @return Optionalx<T>
     */
    public static <T> Optionalx<T> of(T value) {
        return new Optionalx<>(value);
    }

    /**
     * 允许传入空, 方便递归取值后执行操作而不用判空。如：
     * Optionalx.ofEmpty(etBean).map(EtBean::getEtSegmentBeans)
     *             .ifPresentThen(segmentBeans -> segmentBeans.forEach(v -> parseFcPackFare(etBean.getEtBaseBean(), v, fareMap)));
     * @param value value
     * @param <T> value
     * @return Optionalx
     */
    public static <T> Optionalx<T> ofEmpty(T value) {
        if (isNotPresent(value)) {
            return empty();
        }
        return new Optionalx<>(value);
    }

    /**
     * map
     * @param mapper mapper
     * @param <U> U
     * @return Optionalx<U>
     */
    public<U> Optionalx<U> map(Function<? super T, ? extends U> mapper) {
        Objects.requireNonNull(mapper);
        if (!isPresent(value)) {
            return empty();
        } else {
            return Optionalx.ofEmpty(mapper.apply(value));
        }
    }

    /**
     * empty
     * @param <T> T
     * @return Optionalx<T>
     */
    public static<T> Optionalx<T> empty() {
        @SuppressWarnings("unchecked")
        Optionalx<T> t = (Optionalx<T>) EMPTY;
        return t;
    }

    /**
     * ifPresentThen
     * @param consumer consumer
     */
    public void ifPresentThen(Consumer<T> consumer) {
        if (isPresent(this.value)) {
            consumer.accept(this.value);
        }
    }

    /**
     * value如果是空就返回传入的值，否则返回value
     * @param other other
     * @return value or other
     */
    public T orElse(T other) {
        return isPresent(value) ? value : other;
    }

    /**
     * 构造方法
     */
    private Optionalx() {
        this.value = null;
    }

    /**
     * 构造方法
     * @param value value
     */
    private Optionalx(T value) {
        this.value = Objects.requireNonNull(value);
    }

    /**
     * 无异常执行
     * @param r
     * @param emsg
     */
    public static void exec(RunnableNoThrow r, String emsg){
        try {
            r.run();
        } catch (Exception e) {
            System.out.println(emsg+e.getMessage());
        }
    }

    public interface RunnableNoThrow{
        void run() throws Exception;
    }

    /**
     * 判断泛型对象是否为空
     * @param collection 集合
     * @return 结果
     */
    private static boolean isEmpty(Collection<?> collection) {
        if (isNull(collection)) {
            return true;
        }
        return collection.isEmpty();
    }

    /**
     * 判断传入的所有字符串都是空
     *
     * @param strs 字符串列表
     * @return 结果
     */
    private static boolean isAllEmpty(String... strs) {
        for (String str : strs) {
            boolean empty = isEmpty(str);
            if (!empty) {
                return false;
            }
        }
        return true;
    }

    /**
     * 判断对象是否为空
     *
     * @param str 原始字符串
     * @return boolean 结果
     */
    private static boolean isEmpty(String str) {
        if (str == null || str.trim().isEmpty() || "null".equals(str) || "undefined".equals(str)) {
            return true;
        }
        return false;
    }

    /**
     * 判断对象是否为空
     *
     * @param o 原始对象
     * @return 结果
     */
    private static boolean isEmpty(Object o) {
        if(isNull(o)){
            return true;
        }
        if(o instanceof String){
            return isEmpty((String)o);
        }
        if(o instanceof Collection){
            return isEmpty((Collection)o);
        }
        if(o instanceof Map){
            return isEmpty((Map)o);
        }
        if(o.getClass().isArray()){
            return isEmpty((Object[])o);
        }
        return isEmpty(o + "");
    }

    /**
     * 判断是否为null
     *
     * @param obj obj 判断对象
     * @return boolean 是否为null
     */
    private static boolean isNull(Object obj) {
        return obj == null;
    }

    /**
     * 判断对象不是null
     *
     * @param obj 判断对象
     * @return 结果
     */
    private static boolean isNotNull(Object obj){
        return !isNull(obj);
    }
    /**
     * 判断对象是否为空
     *
     * @param map 原始Map
     * @return boolean
     */
    private static boolean isEmpty(Map map) {
        return isNull(map) || map.isEmpty();
    }

    /**
     * 判断对象是否为空
     *
     * @param array array
     * @return boolean
     */
    private static boolean isEmpty(Object[] array) {
        return isNull(array) || array.length == 0;
    }

    /**
     * 不为空
     *
     * @param o o
     * @return boolean
     */
    private static boolean isNotEmpty(Object o) {
        return !isEmpty(o);
    }

    /**
     * 判断数组是否为空
     * @param o 原始数组
     * @return 结果
     */
    private static boolean isNotEmpty(Object[] o) {
        return !isEmpty(o);
    }

    /**
     * 不为空
     *
     * @param o o
     * @return boolean
     */
    private static boolean isNotEmpty(String o) {
        return !isEmpty(o);
    }

    /**
     * 判断集合不为空
     * @param collection 集合
     * @return 结果
     */
    private static boolean isNotEmpty(Collection<?> collection) {
        return !isEmpty(collection);
    }
}
